package com.jeesite.modules.dataScreen.service.impl;

import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import com.jeesite.modules.dataScreen.constants.BgManageExceptions;
import com.jeesite.modules.dataScreen.dao.SysRoleDao;
import com.jeesite.modules.dataScreen.dao.SysRoleMenuDao;
import com.jeesite.modules.dataScreen.dao.SysUserRoleDao;
import com.jeesite.modules.dataScreen.entity.SysMenu;
import com.jeesite.modules.dataScreen.entity.SysRole;
import com.jeesite.modules.dataScreen.entity.SysRoleMenu;
import com.jeesite.modules.dataScreen.entity.SysUserRole;
import com.jeesite.modules.dataScreen.exceptions.BgManageException;
import com.jeesite.modules.dataScreen.service.SysMenuService;
import com.jeesite.modules.dataScreen.service.SysRoleService;
import com.jeesite.modules.dataScreen.web.dto.RoleSearchDto;
import com.jeesite.modules.dataScreen.web.dto.SysRoleDto;
import com.jeesite.modules.dataScreen.web.vo.LoginVo;
import com.jeesite.modules.dataScreen.web.vo.SysRoleVo;
import org.assertj.core.util.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色(SysRole)表服务实现类
 *
 * @since 2024-09-24 15:29:55
 */
@Service("sysRoleService")
public class SysRoleServiceImpl extends ServiceImpl<SysRoleDao, SysRole> implements SysRoleService, StpInterface {


    @Resource
    private SysRoleMenuDao sysRoleMenuDao;
    @Resource
    private SysMenuService sysMenuService;

    @Resource
    private SysUserRoleDao sysUserRoleDao;

    @Override
    public void loginAfterRole(Integer userId, LoginVo loginVo) {

        List<SysRole> roles = getBaseMapper().findAllByUserId(userId);
        if (CollUtil.isEmpty(roles)) {
            //没有分配角色
            throw BgManageExceptions.ACCESS_DENIED;
        }
        Optional<SysRole> first = roles.stream().filter(SysRole::getManagerUser).findFirst();
        if (first.isPresent()) {
            Integer homeUrl = first.get().getHomeUrl();
            SysMenu sysMenu = sysMenuService.findById(homeUrl);
            if (sysMenu != null) {
                loginVo.setHomeUrl(sysMenu.getRoutePath());
                loginVo.setMenus(Sets.newHashSet(sysMenu.getRoutePath()));
            }

            return;
        }
        roles.sort(Comparator.comparing(SysRole::getCreateAt));
        SysRole sysRole = roles.get(0);
        SysMenu sysMenu = sysMenuService.findById(sysRole.getHomeUrl());
        if (sysMenu != null) {
            loginVo.setHomeUrl(sysMenu.getRoutePath());
        }
        //查询菜单
        List<Integer> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toList());
        Set<String> menusStr = getBaseMapper().findAllMenuStrsByRoleId(roleIds);
        loginVo.setMenus(menusStr);
    }

    @Override
    public List<SysRole> listPage(RoleSearchDto dto) {
        LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(dto.getName())) {
            queryWrapper.like(SysRole::getName, dto.getName());
        }
        List<SysRole> roles = list(queryWrapper);
        if (CollUtil.isNotEmpty(roles)) {
            List<Integer> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toList());
            LambdaQueryWrapper<SysRoleMenu> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.in(SysRoleMenu::getRoleId, roleIds);
            List<SysRoleMenu> sysRoleMenus = sysRoleMenuDao.selectList(queryWrapper1);
            Map<Integer, Set<Integer>> map = new HashMap<>();
            for (SysRoleMenu menu : sysRoleMenus) {
                Set<Integer> set = map.getOrDefault(menu.getRoleId(), new HashSet<>());
                set.add(menu.getMenuId());
                map.put(menu.getRoleId(), set);
            }
            List<Integer> homeUrls = roles.stream().map(SysRole::getHomeUrl).collect(Collectors.toList());
            Map<Integer, String> pathMap = sysMenuService.findRoleHomeUrl(homeUrls);
            for (SysRole role : roles) {
                role.setMenuIds(map.get(role.getId()));
                role.setHomeUrlAddr(pathMap.get(role.getHomeUrl()));
            }
        }
        return roles;
    }

    @Override
    public SysRoleVo findById(Integer id) {
        Optional<SysRole> roleOptional = getOptById(id);
        if (!roleOptional.isPresent()) {
            throw new RuntimeException("数据异常：" + id);
        }
        SysRole sysRole = roleOptional.get();
        SysRoleVo sysRoleVo = new SysRoleVo();
        sysRoleVo.setId(sysRoleVo.getId());
        sysRoleVo.setRemark(sysRole.getRemark());
        sysRoleVo.setName(sysRole.getName());
        sysRoleVo.setHomeUrl(sysRole.getHomeUrl());
        LambdaQueryWrapper<SysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysRoleMenu::getRoleId, sysRole.getId());
        queryWrapper.select(SysRoleMenu::getMenuId);
        List<Integer> menuIds = sysRoleMenuDao.selectObjs(queryWrapper);
        sysRoleVo.setHasMenus(CollUtil.newHashSet(menuIds));
        sysRoleVo.setMenus(sysMenuService.findAll(null));
        return sysRoleVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysRoleDto dto) {
        if (Objects.nonNull(dto.getId()) && dto.getId() == 1) {
            throw BgManageExceptions.ACCESS_DENIED;
        }
        SysRole role = new SysRole();
        role.setId(dto.getId());
        role.setName(dto.getName());
        role.setRemark(dto.getRemark());
        role.setHomeUrl(dto.getHomeUrl());
        role.setDeleted(0);
        role.setManagerUser(false);
        if (dto.getId() == null) {
            role.setCreateAt(new Date());
        }
        role.setUpdateAt(new Date());
        saveOrUpdate(role);
        Integer roleId = role.getId();

        LambdaQueryWrapper<SysRoleMenu> deleteWrapper = new LambdaQueryWrapper<>();
        sysRoleMenuDao.delete(deleteWrapper);

        List<SysRoleMenu> roleMenus = dto.getMenuIds().stream().map(e -> {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(roleId);
            sysRoleMenu.setMenuId(e);
            return sysRoleMenu;
        }).collect(Collectors.toList());
        sysRoleMenuDao.insert(roleMenus);
    }

    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        return Lists.list();
    }

    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        if (StrUtil.equals(loginId.toString(), "1")) {
            return Lists.list("admin");
        }
        return Lists.list();
    }

    @Override
    public void updateByUserId(Integer userId, Integer roleId) {
        LambdaQueryWrapper<SysUserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserRole::getUserId, userId);
        sysUserRoleDao.delete(queryWrapper);
        SysUserRole save = new SysUserRole();
        save.setRoleId(roleId);
        save.setUserId(userId);
        sysUserRoleDao.insert(save);
    }

    @Override
    public void delete(Integer id) {
        //如果存在引用不让删除
        List<String> userNames = getBaseMapper().findUserNames(id);
        if (CollUtil.isNotEmpty(userNames)) {
            String format = StrUtil.format("角色存在用户[{}]引用", CollUtil.join(userNames, ","));
            throw BgManageException.newInstance(format);
        }
        removeById(id);
    }
}

